package password

import (
	"fmt"
	"gitee.com/liumou_site/gcs"
	"gitee.com/liumou_site/glbm"
	"gitee.com/liumou_site/logger"
	"log"
	"os"
	"time"
)

type Reset struct {
	User     string
	Password string
	Sudo     *gcs.ApiShell
}

// NewPasswordReset 生成一个针对特定用户的密码重置对象。
func NewPasswordReset(user string) *Reset {
	// 获取当前日期，并格式化为"YYYYMM"的形式，用于生成密码。
	date := time.Now().Format("200601")
	// 使用日期和固定字符串模板来生成密码。
	password := fmt.Sprintf("%s0nUq9r5Q!aVBEJT", date)
	// 返回包含用户和新生成密码的Reset结构体指针。
	return &Reset{
		User:     user,
		Password: password,
		Sudo:     gcs.NewShell(),
	}
}

// NewPasswordResetWithSuffix 生成一个带有自定义密码后缀的密码重置对象。
func NewPasswordResetWithSuffix(user, suffix string) *Reset {
	// 获取当前日期，并格式化为"20060102"的形式，用于生成密码。
	date := time.Now().Format("20060102")
	// 使用日期和自定义后缀生成密码。
	password := fmt.Sprintf("%s%s", date, suffix)
	// 返回包含用户和新生成密码的Reset结构体指针。
	return &Reset{
		User:     user,
		Password: password,
		Sudo:     gcs.NewShell(),
	}
}

// NewPasswordResetWithPrefix 生成一个带有自定义密码前缀的密码重置对象。
func NewPasswordResetWithPrefix(user, prefix string) *Reset {
	// 获取当前日期，并格式化为"20060102"的形式，用于生成密码。
	date := time.Now().Format("20060102")
	// 使用自定义前缀和日期生成密码。
	password := fmt.Sprintf("%s%s", prefix, date)
	// 返回包含用户和新生成密码的Reset结构体指针。
	return &Reset{
		User:     user,
		Password: password,
		Sudo:     gcs.NewShell(),
	}
}

// AddUser 添加新用户到系统
// 本函数首先检查系统中是否已存在该用户，如果不存在，则创建该用户
// 用户创建时，会自动加入到wheel组，并设置默认的bash shell
func (pr *Reset) AddUser() {
	// 检查用户是否已存在
	cmd := fmt.Sprintf("id %s", pr.User)
	pr.Sudo.RunShell(cmd)
	if pr.Sudo.Err == nil {
		// 如果用户已存在，记录日志并退出函数
		logger.Info("用户已存在")
		return
	}
	// 如果用户不存在，记录日志并创建用户
	logger.Info("正在创建用户:", pr.User)
	cmd = fmt.Sprintf("useradd -m -G wheel -s /bin/bash %s", pr.User)
	pr.Sudo.RunShell(cmd)
	if pr.Sudo.Err != nil {
		// 如果创建用户失败，记录错误日志
		logger.Error("创建用户失败: ", pr.Sudo.Err)
		os.Exit(1)
	}
}

// AddWheel 将用户添加到wheel组
// 该方法通过执行系统命令来检查用户是否已经在wheel组，如果没有，则将其添加到wheel组
func (pr *Reset) AddWheel() {
	// 构建检查用户是否在wheel组的命令
	cmd := fmt.Sprintf("groups %s | grep -v grep | grep wheel", pr.User)
	pr.Sudo.RunShell(cmd)
	// 如果没有错误，说明用户已经在wheel组中
	if pr.Sudo.Err == nil {
		logger.Warn(pr.Sudo.Err)
		// 退出函数
		return
	}
	// 如果用户不在wheel组，构建将用户添加到wheel组的命令
	cmd = fmt.Sprintf("usermod -aG wheel %s", pr.User)
	pr.Sudo.RunShell(cmd)
	// 如果有错误，说明添加失败
	if pr.Sudo.Err != nil {
		// 记录错误日志，说明添加wheel组失败的原因
		logger.Error("添加wheel组失败: %s", pr.Sudo.Err)
		os.Exit(2)
	}
	// 如果没有错误，说明添加成功，记录信息日志
	logger.Info("添加wheel组成功")
}

// ChangeUserPassword 修改用户密码
// 该方法通过构造一个命令行指令来更改用户密码
// 它使用了chpasswd命令，通过管道符将用户名和新密码传递给它
// 参数: 无
// 返回值: 无
func (pr *Reset) ChangeUserPassword() {
	// 构造更改密码的命令行指令
	cmd := fmt.Sprintf("echo '%s:%s' | chpasswd", pr.User, pr.Password)
	pr.Sudo.RunShell(cmd)
	if pr.Sudo.Err != nil {
		// 如果执行失败，记录错误日志
		logger.Error("修改密码失败: ", pr.Sudo.Err)
		return
	}
	// 如果执行成功，记录信息日志
	logger.Info("修改密码成功")
}

// DisableUserSSH 禁止用户通过SSH登录
// 该方法通过修改sshd_config文件，将指定用户添加到DenyUsers列表中，以禁止该用户通过SSH登录
func (pr *Reset) DisableUserSSH() {
	// 创建一个新的服务实例，用于操作sshd服务
	newService := glbm.NewService("sshd", "run")

	// 构建命令以检查用户是否已经在DenyUsers列表中
	cmd := fmt.Sprintf("grep ^DenyUsers | grep %s /etc/ssh/sshd_config", pr.User)
	pr.Sudo.RunShell(cmd)
	if pr.Sudo.Err == nil {
		logger.Warn(pr.Sudo.Err)
		return
	}

	// 如果用户不在DenyUsers列表中，则记录信息并准备禁止用户登录
	logger.Info("正在禁止用户登录:", pr.User)
	// 构建命令以将用户添加到DenyUsers列表中
	cmd = fmt.Sprintf("sed -i 's/^#\\?DenyUsers.*/DenyUsers %s/g' /etc/ssh/sshd_config", pr.User)
	pr.Sudo.RunShell(cmd)
	if pr.Sudo.Err != nil {
		logger.Error("禁止用户登录失败: %v", pr.Sudo.Err)
		return
	}

	// 记录信息，准备重启sshd服务以使更改生效
	logger.Info("正在重启sshd服务")
	newService.ReLoadDaemon()
	// 如果服务重载失败，则记录错误并返回
	if newService.Err != nil {
		logger.Error("重载服务失败: %v", newService.Err)
		return
	}

	// 执行命令以检查sshd配置文件的语法
	cmd = "sshd -t"
	pr.Sudo.RunShell(cmd)

	// 如果配置文件存在问题，则记录错误并终止程序
	if pr.Sudo.Err != nil {
		log.Fatalf("sshd配置文件存在问题,请调整后重启服务生效: %v", pr.Sudo)
	}

	// 重启sshd服务
	newService.ReStart()
	// 如果服务重启失败，则记录错误并返回
	if newService.Err != nil {
		logger.Error("sshd服务重启失败: ", newService.Err)
		os.Exit(4)
	}

	// 记录信息，表示sshd服务重启成功
	logger.Info("sshd服务重启成功")
}
